﻿
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;


namespace CrazyMan.TM.Interface.Domain
{
    /// <summary>
    /// Represents a collection of chip banks.
    /// </summary>
    [DebuggerDisplay("Count = {Count}")]
    public class ChipBankCollection : ICollection<ChipBank>
    {
        //TODO: should we allow more than one chip of a specified denomination??

        private List<ChipBank> _innerList;

        /// <summary>
        /// Creates a new empty chip bank collection.
        /// </summary>
        public ChipBankCollection()
        {
            this._innerList = new List<ChipBank>();
        }

        /// <summary>
        /// Gets the inner list of chip banks.
        /// </summary>
        protected List<ChipBank> InnerList
        {
            get { return this._innerList; }
        }
        
        /// <summary>
        /// Gets the chip bank that contains the specified chip.
        /// </summary>
        /// <param name="chip">The chip to search for in the chip case.</param>
        public ChipBank this[int chipValue]
        {
            get
            {
                if (chipValue < 0)
                    throw new ArgumentOutOfRangeException("chipValue", "Chips can not have a negative value.");

                ChipBank bank = null;
                for (int i = 0; i < this.Count; i++)
                {
                    if (this.InnerList[i].Chip.Value == chipValue)
                    {
                        bank = this.InnerList[i];
                        break;
                    }
                }

                if (bank == null)
                    throw new ArgumentException("The specified chip does not exist in the bank.", "chip");

                return bank;
            }
        }

        /// <summary>
        /// Adds a new chip bank to the collection.
        /// </summary>
        /// <param name="bank">The bank to be added to the collection.</param>
        /// <exception cref="ArgumentNullException">Thrown if a null bank is added.</exception>
        public void Add(ChipBank bank)
        {
            if (bank == null)
                throw new ArgumentNullException("bank", "Can not add a null bank to the collection.");

            this.InnerList.Add(bank);
        }

        /// <summary>
        /// Adds a new chip type to the case.
        /// </summary>
        /// <param name="chip">The type of chip to add to the case</param>
        /// <param name="count">The number of specified chip that will be added to the case.</param>
        public void Add(Chip chip, int count)
        {
            //ensure valid number of chips
            ValidateChipCount(count);

            ChipBank newBank = new ChipBank(chip, count);
            this.InnerList.Add(newBank);
        }

        /// <summary>
        /// Removes all chips banks from the collection.
        /// </summary>
        public void Clear()
        {
            this.InnerList.Clear();
        }

        /// <summary>
        /// Determines whether the bank is in the collection.
        /// </summary>
        /// <param name="bank">The bank to search for.</param>
        /// <returns>True if the bank exists in the </returns>
        public bool Contains(ChipBank bank)
        {
            return this.InnerList.Contains(bank);
        }
        
        /// <summary>
        /// Checks if a specified chip exists in the case.
        /// </summary>
        /// <param name="chip">The chip to search for.</param>
        /// <returns>True if the chip exists in the case, else false.</returns>
        public bool Contains(Chip chip)
        {
            ValidateChip(chip);

            for (int i = 0; i < this.Count; i++)
            {
                if (this.InnerList[i].Chip == chip)
                {
                    return true;
                }
            }

            return false;
        }

        /// <summary>
        /// Copies the entire collection to a compatable array, starting at the specified index in the target array.
        /// </summary>
        /// <param name="array">The one dimensional array the items will be copied to.</param>
        /// <param name="arrayIndex">The zero-base index in the array that copy begins.</param>
        public void CopyTo(ChipBank[] array, int arrayIndex)
        {
            this.InnerList.CopyTo(array, arrayIndex);
        }

        /// <summary>
        /// Gets the number of chip banks in the collection.
        /// </summary>
        public int Count
        {
            get { return this.InnerList.Count; }
        }

        /// <summary>
        /// Gets whether the chip bank is read only.
        /// </summary>
        public bool IsReadOnly
        {
            get { return false; }
        }

        /// <summary>
        /// Removes the specified chip bank from the collection.
        /// </summary>
        /// <param name="bank">The chip bank to be removed from the collection.</param>
        /// <returns>True if the bank existed in the collection, else false.</returns>
        public bool Remove(ChipBank bank)
        {
            if (bank == null)
                throw new ArgumentNullException("bank", "Can not remove a null bank from the collection.");

            return this.InnerList.Remove(bank);
        }

        /// <summary>
        /// Returns an enumerator that iterates through the collection.
        /// </summary>
        public IEnumerator<ChipBank> GetEnumerator()
        {
            return this.InnerList.GetEnumerator();
        }

        /// <summary>
        /// Returns an enumerator that iterates through the collection.
        /// </summary>
        IEnumerator IEnumerable.GetEnumerator()
        {
            return this.InnerList.GetEnumerator();
        }

        /// <summary>
        /// Validates that the chip count is legal.
        /// </summary>
        /// <param name="chipCount">The chip count to be validated.</param>
        protected void ValidateChipCount(int chipCount)
        {
            if (chipCount < 0)
                throw new ArgumentOutOfRangeException("chipCount", "The chip count can not be null.");
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="chip"></param>
        protected void ValidateChip(Chip chip)
        {
            if (chip == null)
                throw new ArgumentNullException("chip", "The chip can not be null.");
        }
    }
}
